//
//  TBLoaderURLConnection.m
//  avplayerSavebufferData
//
//  Created by qianjianeng on 15/9/15.
//  Copyright (c) 2015年 qianjianeng. All rights reserved.
//
//// github地址：https://github.com/suifengqjn/TBPlayer

#import "TBLoaderURLConnection.h"
#import <Foundation/Foundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import "TBVideoRequestTask.h"

@interface TBLoaderURLConnection ()<TBVideoRequestTaskDelegate>

@property (nonatomic, strong) NSMutableArray *pendingRequests;
@property (nonatomic, copy  ) NSString       *videoPath;

@end

@implementation TBLoaderURLConnection

- (instancetype)init
{
    self = [super init];
    if (self) {
        _pendingRequests = [NSMutableArray array];
        NSString *document = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
        _videoPath = [document stringByAppendingPathComponent:@"temp.mp3"];
    }
    return self;
}

- (void)fillInContentInformation:(AVAssetResourceLoadingContentInformationRequest *)contentInformationRequest
{
    NSString *mimeType = self.task.mimeType;
    CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(mimeType), NULL);
    contentInformationRequest.byteRangeAccessSupported = YES;
    contentInformationRequest.contentType = CFBridgingRelease(contentType);
    contentInformationRequest.contentLength = self.task.videoLength;
}

+ (void)fillInContentInformation:(AVAssetResourceLoadingContentInformationRequest *)contentInformationRequest mimeType:(NSString *)mimeType videoLength:(NSUInteger)videoLength
{
	CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(mimeType), NULL);
	contentInformationRequest.byteRangeAccessSupported = YES;
	contentInformationRequest.contentType = CFBridgingRelease(contentType);
	contentInformationRequest.contentLength = videoLength;
}

#pragma mark - AVURLAsset resource loader methods

- (void)processPendingRequests
{
    NSMutableArray *requestsCompleted = [NSMutableArray array];  //请求完成的数组
    //每次下载一块数据都是一次请求，把这些请求放到数组，遍历数组
    for (AVAssetResourceLoadingRequest *loadingRequest in self.pendingRequests)
    {
        [self fillInContentInformation:loadingRequest.contentInformationRequest]; //对每次请求加上长度，文件类型等信息
        
        BOOL didRespondCompletely = [self respondWithDataForRequest:loadingRequest.dataRequest]; //判断此次请求的数据是否处理完全
        
        if (didRespondCompletely) {

            [requestsCompleted addObject:loadingRequest];  //如果完整，把此次请求放进 请求完成的数组
            [loadingRequest finishLoading];
            
        }
    }
	
//	NSLog(@"%zd", requestsCompleted.count);

    [self.pendingRequests removeObjectsInArray:requestsCompleted];   //在所有请求的数组中移除已经完成的
    
}


- (BOOL)respondWithDataForRequest:(AVAssetResourceLoadingDataRequest *)dataRequest
{
	
//	NSLog(@"currentOffset = %zd   requestedLength = %zd   requestedOffset = %zd", dataRequest.currentOffset, dataRequest.requestedLength, dataRequest.requestedOffset);
	
    long long startOffset = dataRequest.requestedOffset;

	NSLog(@"startOffset = %zd", startOffset);
	
    if (dataRequest.currentOffset != 0) {
        startOffset = dataRequest.currentOffset;
    }
	
//	NSLog(@"startOffset = %zd    dataRequest.currentOffset = %zd", startOffset, dataRequest.currentOffset);
	
    if ((self.task.offset +self.task.downloadingOffset) < startOffset)
    {
        //NSLog(@"NO DATA FOR REQUEST");
        return NO;
    }
    
    if (startOffset < self.task.offset) {
        return NO;
    }
    
    NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:_videoPath] options:NSDataReadingMappedIfSafe error:nil];
    
    // This is the total data we have from startOffset to whatever has been downloaded so far
    NSUInteger unreadBytes = self.task.downloadingOffset - ((NSInteger)startOffset - self.task.offset);
	
	NSLog(@"length = %zd    downloadingOffset = %zd   startOffset = %zd   offset = %zd", fileData.length, self.task.downloadingOffset, startOffset, self.task.offset);
	
    // Respond with whatever is available if we can't satisfy the request fully yet
    NSUInteger numberOfBytesToRespondWith = MIN((NSUInteger)dataRequest.requestedLength, unreadBytes);
	
	NSLog(@"numberOfBytesToRespondWith = %zd", numberOfBytesToRespondWith);
	
//	NSLog(@"unreadBytes = %zd    numberOfBytesToRespondWith = %zd", unreadBytes, numberOfBytesToRespondWith);
	
    [dataRequest respondWithData:[fileData subdataWithRange:NSMakeRange((NSUInteger)startOffset- self.task.offset, (NSUInteger)numberOfBytesToRespondWith)]];
    
    
    
    long long endOffset = startOffset + dataRequest.requestedLength;
	
	NSLog(@"endOffset = %zd  dataRequest.requestedLength = %zd", endOffset, dataRequest.requestedLength);
	
    BOOL didRespondFully = (self.task.offset + self.task.downloadingOffset) >= endOffset;
	NSLog(@"self.task!.offset = %zd   self.task!.downloadingOffset = %zd   endOffset = %zd", self.task.offset, self.task.downloadingOffset, endOffset);
	
    return didRespondFully;
  
    
}


/**
 *  必须返回Yes，如果返回NO，则resourceLoader将会加载出现故障的数据
 *  这里会出现很多个loadingRequest请求， 需要为每一次请求作出处理
 *  @param resourceLoader 资源管理器
 *  @param loadingRequest 每一小块数据的请求
 *
 */
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
	NSLog(@"add loadingRequest");
	
	AVAssetResourceLoadingDataRequest *dataRequest = loadingRequest.dataRequest;
//	NSLog(@"currentOffset = %zd   requestedLength = %zd   requestedOffset = %zd", dataRequest.currentOffset, dataRequest.requestedLength, dataRequest.requestedOffset);

	
    [self.pendingRequests addObject:loadingRequest];
    [self dealWithLoadingRequest:loadingRequest];
    NSLog(@"----%@", loadingRequest);
    return YES;
}


- (void)dealWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
    NSURL *interceptedURL = [loadingRequest.request URL];
	
	NSLog(@"%zd  %zd  %zd  %ld", loadingRequest.dataRequest.currentOffset, loadingRequest.dataRequest.requestedLength, loadingRequest.dataRequest.requestedOffset, NSIntegerMax);
	
    NSRange range = NSMakeRange((NSUInteger)loadingRequest.dataRequest.currentOffset, NSIntegerMax);
	NSLog(@"%zd  %zd", range.location, range.length);
    if (self.task.downloadingOffset > 0) {
        [self processPendingRequests];
    }
    
    if (!self.task) {
        self.task = [[TBVideoRequestTask alloc] init];
        self.task.delegate = self;
        [self.task setUrl:interceptedURL offset:0];
    } else {
        // 如果新的rang的起始位置比当前缓存的位置还大300k，则重新按照range请求数据
		NSLog(@"==>  %zd", self.task.offset + self.task.downloadingOffset + 1024 * 300 < range.location);
		NSLog(@"==>  %zd", range.location);
		NSLog(@"==>  %zd", self.task.offset);
        if (self.task.offset + self.task.downloadingOffset + 1024 * 300 < range.location ||
            // 如果往回拖也重新请求
            range.location < self.task.offset) {
            [self.task setUrl:interceptedURL offset:range.location];
        }
    }
    
    
}


- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
    [self.pendingRequests removeObject:loadingRequest];
    
}

- (NSURL *)getSchemeVideoURL:(NSURL *)url
{
    NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO];
    components.scheme = @"streaming";
    return [components URL];
}

#pragma mark - TBVideoRequestTaskDelegate

- (void)task:(TBVideoRequestTask *)task didReceiveVideoLength:(NSUInteger)ideoLength mimeType:(NSString *)mimeType
{
   
}

- (void)didReceiveVideoDataWithTask:(TBVideoRequestTask *)task
{
    [self processPendingRequests];
    
}

- (void)didFinishLoadingWithTask:(TBVideoRequestTask *)task
{
    if ([self.delegate respondsToSelector:@selector(didFinishLoadingWithTask:)]) {
        [self.delegate didFinishLoadingWithTask:task];
    }
}

- (void)didFailLoadingWithTask:(TBVideoRequestTask *)task WithError:(NSInteger)errorCode
{
    if ([self.delegate respondsToSelector:@selector(didFailLoadingWithTask:WithError:)]) {
        [self.delegate didFailLoadingWithTask:task WithError:errorCode];
    }
    
}
@end
